﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace PluginDB
{
    public class MoviesRepository
    {
        private readonly Repository<Video, PluginDbEntities> _videoRepository;
        private readonly Repository<VideosLink, PluginDbEntities> _videosLinkRepository;
        private readonly CommonRepository _commonRepository;

        private readonly Repository<ValidVideosView, PluginDbEntities> _validVideosViewRepository;

        public MoviesRepository(PluginDbEntities pluginDbEntities)
        {
            _videoRepository = new Repository<Video, PluginDbEntities>(pluginDbEntities);
            _videosLinkRepository = new Repository<VideosLink, PluginDbEntities>(pluginDbEntities);
            _commonRepository = new CommonRepository(pluginDbEntities);
            _validVideosViewRepository = new Repository<ValidVideosView, PluginDbEntities>(pluginDbEntities);
        }

        public bool IsMovieExists(string pluginUrl)
        {
            return _videoRepository.DoQuery(
                new Specification<Video>(v => v.PluginUrl.ToLower() == pluginUrl.ToLower())).Any();
        }

        #region Get Methods
        internal IQueryable<ValidVideosView> GetMoviesQuery()
        {
            return _validVideosViewRepository.Session.ValidVideosViews;
        }

        internal List<ValidVideosView> GetMoviesByCategoryId(long categoryId, int page, int pageSize)
        {
            var videos = this.GetMoviesQuery()
                                .Where(v => v.CategoryID == categoryId)
                                .OrderBy(v => v.HebrewVideoName)
                                .Page(page, pageSize);
            return videos.ToList();
        }

        internal List<ValidVideosView> GetAllVideos(int page, int pageSize)
        {
            var videos = this.GetMoviesQuery()
                                .OrderByDescending(v => v.VideoID)
                                .Page(page, pageSize);
            return videos.ToList();
        }

        internal List<ValidVideosView> GetHebDubVideos(int page, int pageSize)
        {
            var videos = this.GetMoviesQuery()
                                .Where(v => v.Is_Heb_Dub == 1)
                                .OrderBy(v => v.HebrewVideoName)
                                .Page(page, pageSize);
            return videos.ToList();
        }

        internal List<ValidVideosView> GetHebSubVideos(int page, int pageSize)
        {
            var videos = this.GetMoviesQuery()
                                .Where(v => v.Is_Heb_Sub == 1)
                                .OrderBy(v => v.HebrewVideoName)
                                .Page(page, pageSize);
            return videos.ToList();
        }

        internal List<ValidVideosView> GetLatestVideosList(int page, int pageSize)
        {
            var videos = this.GetMoviesQuery()
                                .OrderByDescending(v => v.VideoID)
                                .Page(page, pageSize);
            return videos.ToList();
        } 
        #endregion

        internal void AddMovie(PluginVideoInfo pluginVideoInfo)
        {
            try
            {
                var video = new Video
                {
                    VideoID = pluginVideoInfo.VideoID,
                    VideoName = pluginVideoInfo.VideoName,
                    EnglishVideoName = pluginVideoInfo.EnglishVideoName,
                    HebrewVideoName = pluginVideoInfo.HebrewVideoName,
                    ImageUrl = pluginVideoInfo.ImageUrl,
                    PluginUrl = pluginVideoInfo.PluginUrl,
                    Plot = pluginVideoInfo.Plot,
                    Site = _commonRepository.GetSite(pluginVideoInfo.SiteName),
                };

                foreach (var link in pluginVideoInfo.Links)
                {
                    if (link.IsBrokenLink) continue;

                    video.VideosLinks.Add(new VideosLink
                    {
                        LinkURL = link.LinkURL,
                        Source = _commonRepository.GetSource(link.SourceName),
                        IsValid = true,
                        ValidDate = DateTime.Now
                    });
                }

                //If there is no VALID link in video then dont save it
                if (video.VideosLinks.Count == 0)
                {
                    _videoRepository.Delete(video);
                    //_log.WarnFormat("Video:{0} has no valid links. abort saving it.", video.VideoName);
                    return;
                }

                //TODO: add rule to extract category name
                if (pluginVideoInfo.Categories != null)
                {
                    foreach (var category in pluginVideoInfo.Categories)
                    {
                        video.Categories.Add(_commonRepository.GetCategory(category));
                    }
                }

                _videoRepository.Add(video);
                _videoRepository.Save();
            }
            catch (UpdateException ex)
            {
                Console.WriteLine("UpdateException durin update. Ex={0}", ex.InnerException.Message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception durin Save. Ex={0}", ex.InnerException.Message);
            }
        }

        public List<ValidVideosView> GetAtoZMoviesList(string startWord, bool isHebWord, int page, int pageSize)
        {
            var videos = this.GetMoviesQuery()
                                .OrderBy(v => v.HebrewVideoName).ToList();

            if(isHebWord)
                return videos.Where(v => v.HebrewVideoName.StartsWith(startWord)).Page(page, pageSize).ToList();

            return videos.Where(v => v.EnglishVideoName.StartsWith(startWord)).Page(page, pageSize).ToList();
        }

        public List<ValidVideosView> GetMoviesBySite(long siteId, int page, int pageSize)
        {
            var videos = this.GetMoviesQuery()
                                .Where(v => v.SiteID == siteId)
                                .OrderBy(v => v.HebrewVideoName)
                                .Page(page, pageSize);
            return videos.ToList();
        }

        public Video GetMovieByID(long videoId)
        {
            return _videoRepository.Session
                                    .Videos
                                    .Include("VideosLinks")
                                    .Where(v=>v.VideoID == videoId)
                                    .FirstOrDefault();
        }

        public VideosLink GetVideoLinkByID(long linkId)
        {
            var link = _videosLinkRepository.DoQuery(
                new Specification<VideosLink>(v => v.LinkID == linkId)).Include("Video").FirstOrDefault();
            return link;
        }

        public List<ValidVideosView> GetMoviesBySearchText(string searchText, int page, int pageSize)
        {
            var videos = this.GetMoviesQuery()
                                .Where(v => v.VideoName.ToLower().Contains(searchText.ToLower()))
                                .OrderBy(v => v.HebrewVideoName)
                                .Page(page, pageSize);
            return videos.ToList();
        }

        public List<VideosLink> GetAllVideosLinks(bool getOnlyInvalid)
        {
            if(getOnlyInvalid)
                return _videosLinkRepository.Session.VideosLinks.Where(x=> !string.IsNullOrEmpty(x.ErrorText)).ToList();

            return _videosLinkRepository.DoQuery().ToList();
        }

        public void SaveAllVideos()
        {
            //_videosLinkRepository.Save();
            _videoRepository.Save();
        }

        public List<Video> GetAllVideos()
        {
            return _videoRepository.SelectAll().ToList();
        }

        public List<Video> GetMoviesByName(string videoName)
        {
            return _videoRepository.Session.Videos.Where(x => x.VideoName.Equals(videoName)).ToList();
        }

        public List<VideosLink> GetMovieLinksByVideoID(long videoId)
        {
            return _videosLinkRepository.Session.VideosLinks.Where(x => x.Video.VideoID == videoId).ToList();
        }

        public void DeleteVideo(Video movie)
        {
            _videoRepository.Delete(movie);
            _videoRepository.Save();
        }

        public void DeleteVideoLink(VideosLink videosLink)
        {
            _videosLinkRepository.Delete(videosLink);
            _videosLinkRepository.Save();
        }

        public List<Video> GetVideosByUserId(long userId)
        {
            return _videoRepository.Session.Videos.Where(s => s.Users.Any(u => u.UserID == userId)).ToList();
        }

        public bool IsUserVideoExists(long userId, long videoId)
        {
            return _videoRepository.Session.Videos.Where(s => s.Users.Any(u => u.UserID == userId)).Any(v=>v.VideoID == videoId);
        }

        public List<ValidVideosView> GetVideosByVideoId(long videoId)
        {
            return _validVideosViewRepository.Session.ValidVideosViews.Where(v => v.VideoID == videoId).ToList();
        }

        public List<Video> GetAllVideosBySite(long siteId)
        {
            return _videoRepository.Session.Videos.Where(v=>v.Site.SiteID == siteId).ToList();
        }

        public int GetVideosCount()
        {
            return _validVideosViewRepository.Session.ValidVideosViews.Count();
        }

        public int GetUserVideosCount(long userID)
        {
            return _videoRepository.Session.Videos.Count(s => s.Users.Any(u => u.UserID == userID));
        }

        internal List<VideosLink> GetVideosLinksBySourceID(long sourceId)
        {
            return _videosLinkRepository.Session.VideosLinks.Where(v => v.Source.SourceID == sourceId).ToList();
        }
    }
}
